﻿//
// © Algobox Ltd - Benn Eichhorn
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Algobox.Feeds.Finance.MarketData;
using System.Threading;

namespace Algobox.Structure.Finance.Strategies.SmartStoploss
{
    public class SmartStoplossStock : IMarketUpdateBid, IMarketUpdateAsk, IMarketUpdateLast
    {
        #region Constructors

        public SmartStoplossStock(SmartStoplossManagement manager, Algobox.Objects.Finance.Assets.Stock.StockListing stock)
        {
            Manager = manager;
            Stock = stock;
        }

        #endregion
        //////////////////
        #region Member Variables

        private object _lock = new object();
        private Dictionary<SmartStoplossOrder, ISmartStoplossCallback> Orders = new Dictionary<SmartStoplossOrder, ISmartStoplossCallback>();

        #endregion
        //////////////////
        #region Properties

        public Objects.Finance.Assets.Stock.StockListing Stock { get; set; }

        public SmartStoplossManagement Manager { get; set; }

        #endregion
        //////////////////
        #region Functions

        public void AddOrder(SmartStoplossOrder order, ISmartStoplossCallback callback)
        {
            lock (_lock)
            {
                if (Orders.Count == 0)
                {
                    Manager.MarketFeed.SubscribeBid(Stock.Security, this);
                    Manager.MarketFeed.SubscribeAsk(Stock.Security, this);
                    Manager.MarketFeed.SubscribeLast(Stock.Security, this);
                    Orders.Add(order, callback);
                }
                else if (!Orders.ContainsKey(order))
                {
                    Orders.Add(order, callback);
                }
            }
        }

        public void CompletedOrder(SmartStoplossOrder order)
        {
            lock (_lock)
            {
                ISmartStoplossCallback callback;
                if (Orders.TryGetValue(order, out callback))
                {
                    callback.OnSmartStoplossComplete(order);
                    Orders.Remove(order);
                }

                if (Orders.Count == 0)
                {
                    Manager.MarketFeed.UnsubscribeBid(Stock.Security, this);
                    Manager.MarketFeed.UnsubscribeAsk(Stock.Security, this);
                    Manager.MarketFeed.UnsubscribeLast(Stock.Security, this);
                }
            }
        }


        public void OrderFill(SmartStoplossOrder order)
        {
            lock (_lock)
            {
                ISmartStoplossCallback callback;
                if (Orders.TryGetValue(order, out callback))
                {
                    callback.OnSmartStoplossFill(order);
                }
            }
        }


        public void OnPriceBid(Objects.Finance.Assets.Stock.IStock stock, Objects.Finance.Prices.PriceVolume bid)
        {
            if (Monitor.TryEnter(_lock))
            {
                try
                { 
                    Orders.Keys.AsParallel().Where(order => order.IsProfitActive && order.IsBuy).ForAll(order => order.OnPriceBid(bid)); 
                }
                finally
                {
                    Monitor.Exit(_lock);
                }
            }
            else
            {
                System.Diagnostics.Debug.Fail("Failed to aquire lock");
            }
        }

        public void OnPriceAsk(Objects.Finance.Assets.Stock.IStock stock, Objects.Finance.Prices.PriceVolume ask)
        {
            if (Monitor.TryEnter(_lock))
            {
                try
                {
                    Orders.Keys.AsParallel().Where(order => order.IsProfitActive && !order.IsBuy).ForAll(order => order.OnPriceAsk(ask));
                }
                finally
                {
                    Monitor.Exit(_lock);
                }
            }
            else
            {
                System.Diagnostics.Debug.Fail("Failed to aquire lock");
            }
        }

        public void OnPriceLast(Objects.Finance.Assets.Stock.IStock stock, Objects.Finance.Prices.PriceVolume last)
        {
            if (Monitor.TryEnter(_lock))
            {
                try
                {
                    Orders.Keys.AsParallel().Where(order => order.IsProfitActive).ForAll(order => order.OnPriceLast(last));
                }
                finally
                {
                    Monitor.Exit(_lock);
                }
            }
            else
            {
                System.Diagnostics.Debug.Fail("Failed to aquire lock");
            }
        }

        public void OnPhaseChange()
        {
            if (Monitor.TryEnter(_lock))
            {
                try
                {
                    Orders.Keys.AsParallel().Where(order => order.IsProfitActive).ForAll(order => order.OnPhaseChange());
                }
                finally
                {
                    Monitor.Exit(_lock);
                }
            }
            else
            {
                System.Diagnostics.Debug.Fail("Failed to aquire lock");
            }
        }

        #endregion
        //////////////////
        #region Enums



        #endregion


    }
}
